<template>
  <div class="app-relation-root">
    <div class="setting">
      <el-button @click="getAppRelation">刷新</el-button>
    </div>
    <div class="app-relation-graph-chart" ref="ChartGraphAppRelationRef"></div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useDark } from '@vueuse/core';
import { appRelationApi } from '@/api/app';
import { isNotNull, isNull } from "@/assets/utils/obj";
// echarts
import * as echartTheme from '@/assets/styles/xz/echartTheme';
import * as appTheme from './AppTheme';
import * as echarts from 'echarts/core';
import { TitleComponent, TooltipComponent, LegendComponent } from 'echarts/components';
import { GraphChart } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([TitleComponent, TooltipComponent, LegendComponent, GraphChart, CanvasRenderer]);

const isDark = useDark();

// -------------------- data
const ChartGraphAppRelationRef = ref<any>(null)
let chartGraphAppRelation: any;
let chartData: any = {
  chart: null,
  apps: [],
  links: []
}

const getAppRelation = () => {
  appRelationApi().then(resp => {
    // 设置 apps
    if (isNotNull(resp.data.apps)) {
      chartData.apps = [];
      resp.data.apps.forEach((appName: string) => {

        // 去除重名
        let repeatAppName: boolean = false;
        chartData.apps.forEach((app: any) => {
          if (app.name === appName) {
            repeatAppName = true;
            return;
          }
        })
        if (repeatAppName) return;

        let style: any = appTheme.style(appName);
        let curAppLinkCuunt: number = resp.data.links.filter((app: any) => app.source === appName).length;
        // 形状范围 (6,20)
        let symbolSize: number = Math.min(6 + curAppLinkCuunt * 1.5, 20);
        chartData.apps.push({
          name: appName,
          label: style.labelStyle,
          symbol: style.symbol,
          symbolSize: symbolSize,
          itemStyle: { color: style.color },
        });
      })
    }

    /**
     * 设置 links
     * 
     * link.source: 连线的源头
     * link.target: 连线的目标
     * link.type: 多种请求方式
     *  - rocketmq: MQ的连线样式进行特殊处理, 并在连线上增加通信的 [TOPIC] 名称
     *  - rpc:
     *  - feign:
     *  - gateway:
     * link.lineStyle.curveness: 曲度，支持从 0 到 1 的值，值越大曲度越大。不同的连线类型有不同的曲度, 相同的两个应用之间方向不同也有不同的曲度。防止连线重叠。
     *                           不同的曲度由后台传入的 link.num 来
     */
    if (isNotNull(resp.data.links)) {
      chartData.links = [];
      resp.data.links.forEach((link: any) => {
        let style = appTheme.style(link.source);
        let lineStyle = {
          color: style.lineColor,
          width: style.lineWidth,
          opacity: style.opacity,
          curveness: (link.num * 0.08)
        };

        // mq
        if (link.type === 'rocketmq') {
          link['label'] = { show: true, formatter: '{c}', color: echartTheme.common().legendColor };
          link['lineStyle'] = { ...lineStyle, ...{ type: 'dashed' } };
        }
        // rpc
        else if (link.type === 'rpc' || link.type === 'feign' || link.type === 'gateway') {
          if (link.source === link.target) { return; }
          link['lineStyle'] = lineStyle;
        }
        chartData.links.push(link);
      })
    }
    renderChart();
  })
}

const renderChart = () => {
  chartGraphAppRelation.setOption({
    title: { text: '应用调用拓扑图', top: '0', left: '0' },
    tooltip: echartTheme.tooltip(),
    legend: [{
      top: 40, left: 0, orient: 'vertical', textStyle: echartTheme.legend().textStyle,
      itemStyle: { shadowColor: 'rgba(0, 0, 0, 0.5)', shadowBlur: 10, shadowOffsetX: 3, shadowOffsetY: 3, },
    }],
    series: [
      {
        type: 'graph', layout: 'force',
        top: 100, bottom: 100,
        force: { repulsion: 35, friction: 0.3 },
        // symbolSize: 8,
        animation: false,
        animationThreshold: 100,
        animationDuration: 1000,
        zoom: 8, roam: true,
        label: {
          show: true,
          fontFamily: echartTheme.common().fontFamily,
          formatter: (params: any) => {
            return params.name.replaceAll('-', '').replaceAll('backend', '').replaceAll('expand', '');
          }
        },
        itemStyle: {
          shadowColor: echartTheme.graph().itemShadowColor,
          shadowBlur: 15, shadowOffsetX: 5, shadowOffsetY: 5,
        },
        lineStyle: { cap: 'round', curveness: 0.1 },
        // 箭头的开始, 结束图形
        edgeSymbol: ['circle', 'arrow'],
        // 箭头的开始, 结束图形大小
        edgeSymbolSize: [0, 7],
        edgeLabel: { fontSize: 10 },
        emphasis: {
          focus: 'adjacency',
          blurScope: 'global',
          lineStyle: { width: 4, opacity: 1 },
          edgeLabel: { fontSize: 13 }
        },
        blur: {
          label: { show: false }, edgeLabel: { show: false },
        },
        data: chartData.apps,
        links: chartData.links,
        categories: chartData.apps
      }
    ]
  });
}

const init = () => {
  chartGraphAppRelation = echarts.init(ChartGraphAppRelationRef.value);
}

const windowResize = () => {
  chartGraphAppRelation.resize();
}

onMounted(() => {
  init();
  windowResize();
  getAppRelation();
})


</script>

<style scoped lang="scss">
.app-relation-root {
  @include box(100%, 100%);
  position: relative;

  .setting {
    position: absolute;
    z-index: 99;
    left: 150px;
  }

  .app-relation-graph-chart {
    @include box(100%, 100%);
  }
}
</style>